﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace PuyoNeuron
{
    public class Constant : Panel
    {
        string mValue;
        static Texture2D sConstantTexture;

        TextEditor mTextEditor;

        public override string Constructor
        {
            get { return "Constant_" + GetHashCode() + ":new()"; }
        }

        public override string Code
        {
            get
            {
                return "Constant_" + GetHashCode() + " = {}\n"
                       + "function Constant_" + GetHashCode() + ":new()\n"
                       + "  local o = {}\n"
                       + "  function o:value()\n"
                       + "    return " + (mValue.Trim().StartsWith("\"") ? mValue.Replace("\\", "\\\\").Replace("\n", "\\n") : mValue) + "\n"
                       + "  end\n"
                       + "  return o\n"
                       + "end";
            }
        }

        public override Vector2 Size
        {
            get { return mSize; }
            set { mSize = new Vector2((value.X <= 20) ? 20 : (int)value.X, (value.Y <= 40) ? 40 : (int)value.Y); }
        }

        public static Texture2D ConstantTexture
        {
            get { return sConstantTexture; }
            set { sConstantTexture = value; }
        }

        public Constant(Vector2 pLocation)
            : base("lua/constant.lua", pLocation)
        {
            mValue = "";
            System.Diagnostics.Debug.WriteLine(mValue);
        }

        public override ContextMenu GetContextMenuFor(Vector2 pLocation)
        {
            ContextMenu lRet = new ContextMenu(TopLeft + pLocation);
            bool lNubClicked = false;
            foreach (Nub lNub in mEmitters)
            {
                Nub lNubAnchor = lNub;
                if ((pLocation + TopLeft - lNub.Center).Length() < 9)
                {
                    lRet.Items.Add(new ContextMenu.ContextItem("break all",
                                                               delegate
                                                                   {
                                                                       lNubAnchor.BreakAll();
                                                                   }));


                    foreach (Nub lSingleNub in lNub.Connections.OrderBy(pA => pA.Center.Y))
                    {
                        Nub lSingleNubAnchor = lSingleNub;
                        lRet.Items.Add(new ContextMenu.ContextItem("break " + lSingleNub.Parent.Title,
                                                                   delegate
                                                                       {
                                                                           lSingleNubAnchor.BreakConnection(lNubAnchor);
                                                                       }));
                    }

                    lNubClicked = true;
                }
            }

            if (!lNubClicked)
            {
                lRet.Items.Add(new ContextMenu.ContextItem("edit", delegate {
                    Game1.TextEditor = new TextEditor(mValue, delegate(string pReturn)
                    {
                        mValue = pReturn;
                        CodeModel.Instance.Update(this);
                    });
                }));
                lRet.Items.Add(new ContextMenu.ContextItem("delete", delegate { Dispose = true; }));
            }
            return lRet;
        }

        internal override void Draw(SpriteBatch pSpriteBatch)
        {
            Vector2 lStringSize = LabelFont.MeasureString(mValue);

            Size = new Vector2((int)(Math.Round(lStringSize.X / 20) * 20) + 40, (int)(Math.Round(lStringSize.Y / 20) * 20) + 20);

            #region draw box
            
            // top
            pSpriteBatch.Draw(sConstantTexture,
                              Camera.Instance.ToScreen(TopLeft + new Vector2(Size.X - (lStringSize.X > 30 ? 40 : 20), 0)),
                              lStringSize.X > 30 ? new Rectangle(0, 0, 40, 10) : new Rectangle(20, 0, 20, 10),
                              Color.White,
                              0,
                              Vector2.Zero,
                              new Vector2(1, 1) * Camera.Instance.Zoom,
                              SpriteEffects.None,
                              0f);

            // edge
            for (int i = 0; i < Size.Y - 20; i += 20)
            pSpriteBatch.Draw(sConstantTexture,
                              Camera.Instance.ToScreen(TopLeft + new Vector2(Size.X - 40, 10 + i)),
                              new Rectangle(0, 10, 40, 20),
                              Color.White,
                              0,
                              Vector2.Zero,
                              new Vector2(1, 1) * Camera.Instance.Zoom,
                              SpriteEffects.None,
                              0f);

            // bottom
            pSpriteBatch.Draw(sConstantTexture,
                              Camera.Instance.ToScreen(TopLeft + new Vector2(Size.X - (lStringSize.X > 30 ? 40 : 20), Size.Y - 10)),
                              lStringSize.X > 30 ? new Rectangle(0, 30, 40, 10) : new Rectangle(20, 30, 20, 10),
                              Color.White,
                              0,
                              Vector2.Zero,
                              new Vector2(1, 1) * Camera.Instance.Zoom,
                              SpriteEffects.None,
                              0f);

            #endregion

            #region draw wires

            Nub lHilight = null;
            foreach (Nub lNubA in mEmitters)
            {
                foreach (Nub lNubB in lNubA.Connections)
                {
                    if ((Camera.Instance.ToWorld(new Vector2(Mouse.GetState().X, Mouse.GetState().Y)) - lNubA.Center).Length() < 9)
                        lHilight = lNubA;

                    DrawWire(pSpriteBatch, Camera.Instance.ToScreen(lNubA.Center), Camera.Instance.ToScreen(lNubB.Center), Color.Black);
                    pSpriteBatch.Draw(NubTexture,
                                      Camera.Instance.ToScreen(lNubB.Center - new Vector2(7, 7)),
                                      new Rectangle(0, 0, 14, 14),
                                      Color.White,
                                      0f,
                                      Vector2.Zero,
                                      Camera.Instance.Zoom,
                                      SpriteEffects.None,
                                      0f);
                }
            }

            // draw hilighted wire on top of other wires
            // only draws on top of wires inside this box... but thats not a super huge issue
            if (lHilight != null)
            {
                foreach (Nub lNubB in lHilight.Connections)
                {
                    DrawWire(pSpriteBatch, Camera.Instance.ToScreen(lHilight.Center), Camera.Instance.ToScreen(lNubB.Center), Color.Yellow);
                    pSpriteBatch.Draw(NubTexture,
                                      Camera.Instance.ToScreen(lNubB.Center - new Vector2(7, 7)),
                                      new Rectangle(lNubB.Type == Nub.NubType.Receiver ? 0 : 28, 0, 14, 14),
                                      Color.White,
                                      0f,
                                      Vector2.Zero,
                                      Camera.Instance.Zoom,
                                      SpriteEffects.None,
                                      0f);
                }
            }

            // draw a wire to the cursor
            if (sNewWireStart != null)
                if (sNewWireStart.Type == Nub.NubType.Emitter || sNewWireStart.Type == Nub.NubType.Fire)
                    DrawWire(pSpriteBatch, Camera.Instance.ToScreen(sNewWireStart.Center), new Vector2(Mouse.GetState().X, Mouse.GetState().Y), Color.Yellow);
                else
                    DrawWire(pSpriteBatch, new Vector2(Mouse.GetState().X, Mouse.GetState().Y), Camera.Instance.ToScreen(sNewWireStart.Center), Color.Yellow);

            #endregion

            #region draw nubs

            foreach (Nub lNub in mEmitters)
            {
                pSpriteBatch.Draw(NubTexture, Camera.Instance.ToScreen(lNub.Center - new Vector2(7, 7)), new Rectangle(14, 0, 14, 14), Color.White,
                                  0f,
                                  Vector2.Zero,
                                  Camera.Instance.Zoom,
                                  SpriteEffects.None,
                                  0f);
            }
            #endregion

            pSpriteBatch.DrawString(LabelFont,
                                    mValue,
                                    Camera.Instance.ToScreen(TopLeft + new Vector2(Size.X - lStringSize.X - 15, Size.Y / 2 - lStringSize.Y / 2)),
                                    Color.White,
                                    0f,
                                    Vector2.Zero,
                                    Camera.Instance.Zoom,
                                    SpriteEffects.None,
                                    0f);

            if (mTextEditor != null)
                mTextEditor.Draw(pSpriteBatch);
        }
    }
}
